home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mh / mh-6.8 / support / pop / popser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-14  |  50.2 KB  |  2,349 lines

  1. /* popser.c - the POP service */
  2. #ifndef    lint
  3. static char ident[]="@(#)$Id: popser.c,v 1.29 1992/12/15 00:20:22 jromine Exp $";
  4. #endif
  5.  
  6. #include "../h/mh.h"
  7. #include "../h/dropsbr.h"
  8. #ifdef    MPOP
  9. #ifdef    BPOP
  10. #include "../h/formatsbr.h"
  11. #include "../h/scansbr.h"
  12. #endif
  13. #endif /* MPOP */
  14. #include "../zotnet/bboards.h"
  15. #include <stdio.h>
  16. #include "../zotnet/mts.h"
  17. #include <ctype.h>
  18. #include <errno.h>
  19. #include <pwd.h>
  20. #include <signal.h>
  21. #include "syslog.h"
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #ifdef KPOP
  25. #include <krb.h>
  26. #endif    /* KPOP */
  27. #ifdef    SYS5
  28. #include <fcntl.h>
  29. #endif    /* SYS5 */
  30. #ifdef    SHADOW
  31. #include <shadow.h>
  32. #endif    /* SHADOW */
  33.  
  34.  
  35. #define    TRUE    1
  36. #define    FALSE    0
  37.  
  38. #define    NVEC    5
  39.  
  40. #ifndef    POPSERVICE
  41. #define    POPSERVICE    "pop"
  42. #endif
  43.  
  44. /*   */
  45.  
  46. extern int  errno;
  47.  
  48. extern int  debug;
  49. extern char myhost[];
  50. extern char *myname;
  51.  
  52. #ifndef    POP2
  53. static enum state {
  54.     auth1, auth2, trans, update, halt, error
  55. } mystate;
  56. #else
  57. static enum state {
  58.     auth1, auth2, trans, mbox, item, ack, update, halt, error
  59. } mystate;
  60. #endif
  61.  
  62.  
  63. static int     user (), pass ();
  64. #ifdef    BPOP
  65. static        isguest(), getbbmax();
  66. #ifndef    MPOP
  67. static    int    xtnd1(), xtnd2();
  68. #else
  69. static    int    xtnd1(), xtnd2(), xtnd3 ();
  70. #endif /* MPOP */
  71. #endif    /* BPOP */
  72. #ifdef    RPOP
  73. static int    rpop ();
  74. #endif    /* RPOP */
  75. #ifdef    APOP
  76. static    int    apop ();
  77. #endif
  78. static int     status (), list (), retrieve (), delete (), reset ();
  79. static int    top (), last ();
  80. #ifdef    BPOP
  81. static int    xtnd ();
  82. #endif    /* BPOP */
  83. static int     quit ();
  84. #ifdef    POP2
  85. static int    helo (), rdp2 (), acks (), ack2 (), fold (), nack ();
  86. #endif    /* POP2 */
  87.  
  88. static struct vector {
  89.     char   *v_cmd;
  90.     int     v_min, v_max;
  91.     int     (*v_vec) ();
  92.     enum state v_valid;
  93.     enum state v_win, v_lose;
  94. }               vectors[] = {
  95.     "user", 1, 1, user, auth1, auth2, auth1,
  96.     "pass", 1, 1, pass, auth2, trans, auth1,
  97. #ifdef    RPOP
  98.     "rpop", 1, 1, rpop, auth2, trans, auth1,
  99. #endif    /* RPOP */
  100. #ifdef    APOP
  101.     "apop", 2, 2, apop, auth1, trans, auth1,
  102. #endif
  103.     "quit", 0, 0, NULL, auth1, halt, halt,
  104.     "quit", 0, 0, NULL, auth2, halt, halt,
  105.  
  106.     "stat", 0, 0, status, trans, trans, trans,
  107.     "list", 0, 1, list, trans, trans, trans,
  108.     "retr", 1, 1, retrieve, trans, trans, trans,
  109.     "dele", 1, 1, delete, trans, trans, trans,
  110.     "noop", 0, 0, NULL, trans, trans, trans,
  111.     "rset", 0, 0, reset, trans, trans, trans,
  112.  
  113.     "top",  2, 2, top,  trans, trans, trans,
  114.     "last", 0, 0, last, trans, trans, trans,
  115. #ifdef    BPOP
  116. #ifndef    MPOP
  117.     "xtnd", 1, 2, xtnd, trans, trans, trans,
  118. #else
  119.     "xtnd", 1, 3, xtnd, trans, trans, trans,
  120. #endif /* MPOP */
  121. #endif    /* BPOP */
  122.     "quit", 0, 0, quit, trans, halt, halt,
  123.  
  124. #ifdef    POP2
  125.     "helo", 2, 2, helo, auth1, mbox, auth1,
  126.  
  127.     "fold", 1, 1, fold, mbox, mbox, mbox,
  128.     "quit", 0, 0, quit, mbox, halt, halt,
  129.     "read", 0, 1, rdp2, mbox, item, error,
  130.  
  131.     "fold", 1, 1, fold, item, mbox, mbox,
  132.     "read", 0, 1, rdp2, item, item, error,
  133.     "quit", 0, 0, quit, item, halt, halt,
  134.     "retr", 0, 0, retrieve, item, ack, error,
  135.  
  136.     "acks", 0, 0, ack2, ack, item, error,
  137.     "ackd", 0, 0, ack2, ack, item, error,
  138.     "nack", 0, 0, rdp2, ack, item, error,
  139.     "quit", 0, 0, NULL, ack, halt, halt,
  140.  
  141. #endif    /* POP2 */
  142.     NULL
  143. };
  144.  
  145. static struct vector  *getvector ();
  146.  
  147. /*   */
  148.  
  149. #ifdef    POP2
  150. static int pop2 = NOTOK;    /* current pop2 msg, or NOTOK if pop3 */
  151. #endif    /* POP2 */
  152. #ifdef    DPOP
  153. static int pop_uid;
  154. static int pop_gid;
  155. #endif    /* DPOP */
  156.  
  157. static int  rproto;
  158. static char *hostname;
  159. static char server[BUFSIZ];
  160. static char timestamp[BUFSIZ];
  161.  
  162. static char username[BUFSIZ];
  163.  
  164. static char maildrop[BUFSIZ];
  165. static int  mode;
  166. static time_t mtime;
  167. static FILE *dp;
  168.  
  169. static long lastseen;
  170. static int  rmsgs;
  171.  
  172. #ifdef    BPOP
  173. static int xtnded;
  174.  
  175. static int guest_uid;
  176. static int guest_gid;
  177.  
  178. static struct bboard *BBhead = NULL;
  179. static struct bboard *BBtail = NULL;
  180.  
  181. static long BBtime = 0L;
  182.  
  183. static struct bboard *getbbaux ();
  184. #endif    /* BPOP */
  185.  
  186.  
  187. struct Msg {            /* Msgs[0] contains info for entire maildrop */
  188.     struct drop m_drop;
  189. #define    m_id    m_drop.d_id
  190. #define    m_size    m_drop.d_size
  191. #define    m_last    m_drop.d_start    /* Msgs[i = 0] */
  192. #define    m_start    m_drop.d_start    /* Msgs[i > 0] */
  193. #define    m_stop    m_drop.d_stop
  194.  
  195.     unsigned    m_flags;
  196. #define    MNULL    0x00
  197. #define    MDELE    0x01
  198. #define    MREAD    0x02
  199. };
  200.  
  201. static int nMsgs = 0;
  202. static struct Msg *Msgs = NULL;
  203.  
  204. static int  nmsgs;
  205. static int  dmsgs;
  206. #ifdef    MPOP
  207. #ifdef    BPOP
  208. static int   _sc_width = 0;
  209. static char *nfs = NULL;
  210. #endif
  211. #endif /* MPOP */
  212.  
  213.  
  214. #define    TRM    "."
  215. #define    TRMLEN    (sizeof TRM - 1)
  216. #define    IAC    255
  217.  
  218. static int    pipeser ();
  219.  
  220. FILE   *input;
  221. FILE   *output;
  222.  
  223. #ifndef    __STDC__
  224. #ifdef    SYS5
  225. struct passwd *getpwnam();
  226. #endif
  227. #endif
  228.  
  229. void    padvise (), padios ();
  230. long    lseek ();
  231. char   *crypt ();
  232.  
  233. #ifdef    POPUUMBOX
  234. #define    MBX_READ    pmbx_read
  235. static    int    pmbx_read ();
  236. static    char   *p_copy(), *p_copyin(), *p_nextword();
  237. static        p_cmatch(), p_isdate(), p_ishead(), p_parse(), any();
  238. #else
  239. #define    MBX_READ    mbx_read
  240. #endif
  241. extern    int    mbx_read ();
  242.  
  243. static int    setup(), setupaux(), read_map(), read_file(), pmbx_size();
  244. static int    quitaux(), quitfile(), respond(), getline();
  245. static    m_gMsgs(), multiline(), multiend(), putline();
  246. /*   */
  247.  
  248. popinit () {
  249. #ifdef    BPOP
  250.     padvise (NULLCP, LOG_INFO, "initialize list of BBoards");
  251.  
  252.     BBhead = BBtail = NULL;
  253.     while (getbbaux (NULLCP))
  254.     continue;
  255. #endif    /* BPOP */
  256. }
  257.  
  258. popassert () {
  259. #ifdef    BPOP
  260.     register char **p;
  261.     register struct bboard *bb,
  262.                            *bp;
  263.  
  264.     if (BBtime == getbbtime ())
  265.     return;
  266.  
  267.     padvise (NULLCP, LOG_INFO, "list of BBoards has changed");
  268.  
  269.     for (bb = BBhead; bb; bb = bp) {
  270.     bp = bb -> bb_next;
  271.  
  272.     if (bb -> bb_name)
  273.         free (bb -> bb_name);
  274.     if (bb -> bb_file)
  275.         free (bb -> bb_file);
  276.     if (bb -> bb_archive)
  277.         free (bb -> bb_archive);
  278.     if (bb -> bb_info)
  279.         free (bb -> bb_info);
  280.     if (bb -> bb_map)
  281.         free (bb -> bb_map);
  282.     if (bb -> bb_passwd)
  283.         free (bb -> bb_passwd);
  284.     if (bb -> bb_date)
  285.         free (bb -> bb_date);
  286.     if (bb -> bb_addr)
  287.         free (bb -> bb_addr);
  288.     if (bb -> bb_request)
  289.         free (bb -> bb_request);
  290.     if (bb -> bb_relay)
  291.         free (bb -> bb_relay);
  292.  
  293.     for (p = bb -> bb_aka; *p; p++)
  294.         free (*p);
  295.     free ((char *) bb -> bb_aka);
  296.  
  297.     for (p = bb -> bb_leader; *p; p++)
  298.         free (*p);
  299.     free ((char *) bb -> bb_leader);
  300.  
  301.     for (p = bb -> bb_dist; *p; p++)
  302.         free (*p);
  303.     free ((char *) bb -> bb_dist);
  304.  
  305.     free ((char *) bb);
  306.     }
  307.  
  308.     BBhead = BBtail = NULL;
  309.     while (getbbaux (NULLCP))
  310.     continue;
  311. #endif    /* BPOP */
  312. }
  313.  
  314. /*   */
  315.  
  316. #ifdef KPOP
  317. static char *kusername;
  318.  
  319. kpop (in, out, principal, rhost, auth)
  320. int   in,
  321.       out;
  322. char  *principal, *rhost;
  323. int auth;
  324. #else    /* KPOP */
  325. pop (in, out, priv, rhost)
  326. int    in,
  327.     out,
  328.     priv;
  329. char   *rhost;
  330. #endif    /* KPOP */
  331. {
  332.     char    buffer[BUFSIZ],
  333.            *vec[NVEC + 1];
  334. #if    defined (DPOP) || defined (BPOP)
  335.     register struct passwd *pw;
  336. #endif    /* defined (DPOP) || defined (BPOP) */
  337.     register struct vector *v;
  338.  
  339.     m_foil (NULLCP);
  340.     mts_init (myname);
  341.  
  342.     hostname = rhost;
  343. #ifdef KPOP
  344.     rproto = 1;
  345.     (void) sprintf (server, "%s KPOP server", myhost);
  346. #else
  347.     rproto = priv;
  348.     (void) sprintf (server, "%s server", priv ? "RPOP" : "POP");
  349. #endif    /* KPOP */
  350.  
  351.     if ((input = fdopen (in, "r")) == NULL
  352.         || (output = fdopen (out, "w")) == NULL) {/* you lose big */
  353.     (void) respond (NOTOK, "%s loses on initialization", server);
  354.     return;
  355.     }
  356.     (void) signal (SIGPIPE, pipeser);
  357. #ifdef KPOP
  358.     if (principal == NULLCP) {
  359.     char buf[512];
  360.     strcpy(buf,  "Authentication failed: ");
  361.     strcat(buf, krb_err_txt[auth]);
  362.     (void) respond (NOTOK, buf);
  363.     return;
  364.     }
  365.     kusername = principal;
  366. #endif    /* KPOP */
  367.  
  368. #ifdef    DPOP
  369.     if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1)) {
  370.     (void) respond (NOTOK, "%s loses on DB initialization -- %s",
  371.             server, pw ? getbberr () : "POP user-id unknown");
  372.     return;
  373.     }
  374.     pop_uid = pw -> pw_uid;
  375.     pop_gid = pw -> pw_gid;
  376. #endif    /* DPOP */
  377. #ifdef    BPOP
  378.     if ((pw = getpwnam (popbbuser)) && pw -> pw_uid) {
  379.     guest_uid = pw -> pw_uid;
  380.     guest_gid = pw -> pw_gid;
  381.     }
  382.     else
  383.     guest_uid = guest_gid = 0;
  384. #endif    /* BPOP */
  385.  
  386.     {
  387.     long    clock;
  388.  
  389.     (void) time (&clock);
  390.     (void) sprintf (timestamp, "<%d.%ld@%s>", getpid (), clock, myhost);
  391.     }
  392.     (void) respond (OK, "%s ready %s", server, timestamp);
  393.  
  394.     for (mystate = auth1; mystate != halt && mystate != error;)
  395.     switch (getline (buffer, sizeof buffer, input)) {
  396.         case OK: 
  397.         if ((v = getvector (buffer, vec)) == NULL)
  398.             continue;
  399.         mystate = (v -> v_vec ? (v -> v_vec) (vec)
  400.             : respond (OK, NULLCP)) == OK
  401.             ? v -> v_win
  402.             : v -> v_lose;
  403.         break;
  404.  
  405.         case NOTOK: 
  406.         case DONE: 
  407.         mystate = error;
  408.         (void) respond (NOTOK, "%s signing off", server);
  409.         break;
  410.     }
  411. }
  412.  
  413. /*   */
  414. #ifdef    POP2
  415. static int  helo (vec)        /* sort of "user" and "pass" */
  416. register char  **vec;
  417. {
  418.     pop2 = 0;                /* now we're talkin' pop2! */
  419.     make_lower (username, vec[1]);    /* helo user pass */
  420.     return pass (++vec);        /* user pass */
  421. }
  422. #endif
  423.  
  424. static int  user (vec)
  425. register char  **vec;
  426. {
  427.     make_lower (username, vec[1]);
  428. #ifdef KPOP
  429.     if (!strcmp(username, kusername))
  430.       return respond (OK, "Kerberos authentication succeeded. Send username as password (%s)", username);
  431.     else {
  432.     respond (NOTOK, "Wrong username supplied (%s vs. %s)",
  433.          kusername, username);
  434.     return (NOTOK);
  435.     }
  436. #else
  437.     return respond (OK, "password required for %s", username);
  438. #endif
  439. }
  440.  
  441. /*   */
  442.  
  443. static int  pass (vec)
  444. register char  **vec;
  445. {
  446.     int    guest = 0;
  447. #ifndef    DPOP
  448.     register struct passwd *pw;
  449. #ifdef    SHADOW
  450.     register struct spwd *shpw;
  451. #endif    /* SHADOW */
  452. #else    /* DPOP */
  453.     register struct bboard *pw;
  454. #endif    /* DPOP */
  455.  
  456. #ifdef KPOP
  457. #ifndef DPOP
  458.     if ((pw = getpwnam (username)) != NULL)
  459.       return setup(pw, FALSE);
  460.     else
  461.       return respond (NOTOK, "no local password entry");
  462. #else
  463.     {
  464.       static struct bboard entry;
  465.       static char entry_file[BUFSIZ] = "/usr/spool/pop";
  466.       
  467.       pw = &entry;
  468.       pw->bb_name = username;
  469.       strcat(entry_file, username);
  470.       pw->bb_file = entry_file;
  471.       return setup(pw, FALSE);
  472.     }
  473. #endif
  474. #else    /* KPOP */
  475.  
  476. #ifndef    DPOP
  477. #ifdef    BPOP
  478.     if (isguest ()) {
  479. #ifdef    TRUSTED
  480.     static passwd gw;
  481.  
  482.     gw.pw_name = popbbuser;
  483.     gw.pw_uid = guest_uid;
  484.     pw = &gw;
  485. #endif    /* TRUSTED */
  486.     guest = 1;
  487.     goto anonymous;
  488.     }
  489. #endif    /* BPOP */
  490.     if ((pw = getpwnam (username)) == NULL
  491. #ifndef    SHADOW
  492.         || *pw -> pw_passwd == NULL
  493.         || strcmp (crypt (vec[1], pw -> pw_passwd), pw -> pw_passwd)) {
  494. #else    /* SHADOW */
  495.         || (shpw = getspnam (username)) == NULL
  496.         || *shpw -> sp_pwdp == NULL
  497.         || strcmp (crypt (vec[1], shpw -> sp_pwdp), shpw -> sp_pwdp)) {
  498. #endif    /* SHADOW */
  499. #ifdef    TRUSTED
  500.     trusted (0, hostname, NULLCP, 0, pw ? pw -> pw_name : username,
  501.         pw && pw -> pw_uid == 0, POPSERVICE, "tcp", NULL);
  502. #endif    /* TRUSTED */
  503.     return respond (NOTOK, "login incorrect");
  504.     }
  505. #else    /* DPOP */
  506. #ifdef    BPOP
  507.     if (isguest ()) {
  508.     static struct bboard gw;
  509.  
  510.     gw.bb_name = popbbuser;
  511.     pw = &gw;
  512.     guest = 1;
  513.     goto anonymous;
  514.     }
  515. #endif    /* BPOP */
  516.     if (((pw = getbbnam (username)) == NULL
  517.         && (pw = getbbaka (username)) == NULL)
  518.         || *pw -> bb_passwd == NULL
  519.         || strcmp (crypt (vec[1], pw -> bb_passwd), pw -> bb_passwd)) {
  520. #ifdef    TRUSTED
  521.     trusted (0, hostname, NULLCP, 0, pw ? pw -> bb_name : username,
  522.         0, POPSERVICE, "tcp", NULL);
  523. #endif    /* TRUSTED */
  524.     return respond (NOTOK, "login incorrect");
  525.     }
  526. #endif    /* DPOP */
  527.  
  528. #ifdef    BPOP
  529. anonymous: ;
  530. #endif    /* BPOP */
  531. #ifdef    TRUSTED
  532.     if (trusted (1, hostname, NULLCP, 0, myhost,
  533. #ifndef    DPOP
  534.         pw -> pw_name, pw -> pw_uid == 0,
  535. #else    /* DPOP */
  536.         pw -> bb_name, 0,
  537. #endif    /* DPOP */
  538.         POPSERVICE, "tcp", NULL)
  539.         == 0)
  540.     return respond (NOTOK, "permission denied");
  541. #endif    /* TRUSTED */
  542.     return setup (pw, guest);
  543. #endif /* KPOP */
  544. }
  545.  
  546. /*   */
  547.  
  548. #ifdef    BPOP
  549. static  isguest () {
  550.     int        i;
  551.     register char  *cp;
  552.     char    buffer[BUFSIZ];
  553.     register FILE  *fp;
  554.  
  555.     if (strcmp (username, popbbuser) || !guest_uid)
  556.     return FALSE;
  557.     if (popbblist == NULL || (fp = fopen (popbblist, "r")) == NULL)
  558.     return TRUE;
  559.  
  560.     i = FALSE;
  561.     if (hostname)
  562.     while (fgets (buffer, sizeof buffer, fp)) {
  563.         if (cp = index (buffer, '\n'))
  564.         *cp = NULL;
  565.         if (strcmp (buffer, hostname) == 0) {
  566.         i = TRUE;
  567.         break;
  568.         }
  569.     }
  570.  
  571.     (void) fclose (fp);
  572.  
  573.     return i;
  574. }
  575. #endif    /* BPOP */
  576.  
  577. /*   */
  578.  
  579. #ifdef    RPOP
  580. static int rpop (vec)
  581. register char  **vec;
  582. {
  583. #ifndef    DPOP
  584.     register struct passwd *pw;
  585. #else    /* DPOP */
  586.     register int hostok = 0;
  587.     register char  *bp,
  588.            *cp;
  589.     char    buffer[BUFSIZ];
  590.     register struct bboard *pw;
  591. #endif    /* DPOP */
  592.  
  593. #ifndef    DPOP
  594.     if (!rproto || (pw = getpwnam (username)) == NULL) {
  595. #ifdef    TRUSTED
  596.     trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp",
  597.         NULL);
  598. #endif    /* TRUSTED */
  599.     return respond (NOTOK, "login incorrect");
  600.     }
  601.     if (chdir (pw -> pw_dir) == NOTOK && chdir ("/") == NOTOK)
  602.     return respond (NOTOK, "no remote directory");
  603.     if (ruserok (hostname, pw -> pw_uid == 0, vec[1], username) == NOTOK) {
  604. #ifdef    TRUSTED
  605.     trusted (0, hostname, vec[1], 0, pw -> pw_name,
  606.        pw -> pw_uid == 0, "rpop", "tcp", NULL);
  607. #endif    /* TRUSTED */
  608.     return respond (NOTOK, "permission denied");
  609.     }
  610. #else    /* DPOP */
  611.     if (!rproto
  612.         || ((pw = getbbnam (username)) == NULL
  613.         && (pw = getbbaka (username)) == NULL)) {
  614. #ifdef    TRUSTED
  615.     trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp",
  616.         NULL);
  617. #endif    /* TRUSTED */
  618.     return respond (NOTOK, "login incorrect");
  619.     }
  620. /*
  621.  * hacked by Dave Cohrs Tue Feb  4 14:12:15 CST 1986
  622.  *   to allow the hostname to be a list: user@host1,user@host2
  623.  *   NOTE: the separator must be a comma -- no spaces are allowed
  624.  */
  625.     (void) sprintf (buffer, "%s@%s", vec[1], hostname);
  626.     for (bp = pw -> bb_addr; bp; bp = cp) {
  627.     if ((cp = index (bp, ',')))
  628.         *cp = 0;
  629.     hostok = uleq (bp, buffer);
  630.     if (cp)
  631.         *cp++ = ',';
  632.     if (hostok)
  633.         break;
  634.     }
  635.     if (!hostok) {
  636. #ifdef    TRUSTED
  637.     trusted (0, hostname, vec[1], 0, pw -> bb_name, 0, "rpop",
  638.         "tcp", NULL);
  639. #endif    /* TRUSTED */
  640.     return respond (NOTOK, "permission denied");
  641.     }
  642. #endif    /* DPOP */
  643.  
  644. #ifdef    TRUSTED
  645.     if (trusted (1, hostname, vec[1], 0, username,
  646. #ifndef    DPOP
  647.         pw -> pw_uid == 0,
  648. #else    /* DPOP */
  649.         0,
  650. #endif    /* DPOP */
  651.         "rpop", "tcp", NULL)
  652.         == 0)
  653.     return respond (NOTOK, "permission denied");
  654. #endif    /* TRUSTED */
  655.     return setup (pw, FALSE);
  656. }
  657. #endif    /* RPOP */
  658.  
  659. /*   */
  660.  
  661. #ifdef    APOP
  662. #include "popauth.h"
  663. #include "../../uip/md5.c"
  664. #include <ndbm.h>
  665. #include <sys/file.h>
  666. #ifdef    SYS5
  667. #include <fcntl.h>
  668. #endif
  669.  
  670.  
  671. static int apop (vec)
  672. register char  **vec;
  673. {
  674.     register char *cp;
  675.     char    buffer[BUFSIZ];
  676.     register unsigned char *dp;
  677.     unsigned char *ep,
  678.            digest[16];
  679. #ifndef    DPOP
  680.     register struct passwd *pw;
  681. #else
  682.     register struct bboard *pw;
  683. #endif
  684.     struct stat st;
  685.     datum   key,
  686.         value;
  687.     DBM       *db;
  688.     MD5_CTX mdContext;
  689.     struct authinfo auth;
  690.  
  691.     (void) strcpy (username, vec[1]);
  692.  
  693. #ifndef    DPOP
  694.     if ((pw = getpwnam (username)) == NULL
  695.         || *pw -> pw_passwd == NULL) {
  696.     return respond (NOTOK, "user invalid");
  697.     }
  698. #else
  699.     if (((pw = getbbnam (username)) == NULL
  700.         && (pw = getbbaka (username)) == NULL)
  701.         || *pw -> bb_passwd == NULL) {
  702.     return respond (NOTOK, "subscriber invalid");
  703.     }
  704. #endif
  705.  
  706.     if ((db = dbm_open (APOP, O_RDONLY, 0)) == NULL)
  707.     return respond (NOTOK, "POP authorization DB not available (%d)",
  708.             errno);
  709.     if (fstat (dbm_pagfno (db), &st) != NOTOK
  710.         && (st.st_mode & 0777) != 0600) {
  711.     dbm_close (db);
  712.     return respond (NOTOK, "POP authorization DB has wrong mode (0%o)",
  713.             st.st_mode & 0777);
  714.     }
  715.     if (flock (dbm_pagfno (db), LOCK_SH) == NOTOK) {
  716.     dbm_close (db);
  717.     return respond (NOTOK, "unable to lock POP authorization DB (%d)",
  718.             errno);
  719.     }
  720.     key.dsize = strlen (key.dptr = vec[1]) + 1;
  721.     value = dbm_fetch (db, key);
  722.     if (value.dptr == NULL) {
  723.     dbm_close (db);
  724.     return respond (NOTOK, "not authorized");
  725.     }
  726.     bcopy (value.dptr, (char *) &auth, sizeof auth);
  727.     (void) sprintf (cp = buffer, "%s%*.*s", timestamp, auth.auth_secretlen,
  728.             auth.auth_secretlen, auth.auth_secret);
  729.  
  730.     dbm_close (db);
  731.  
  732.     MD5Init (&mdContext);
  733.     MD5Update (&mdContext, (unsigned char *) buffer,
  734.            (unsigned int) (strlen (timestamp) + auth.auth_secretlen));
  735.     MD5Final (digest, &mdContext);
  736.  
  737.     cp = buffer;
  738.     for (ep = (dp = digest) + sizeof digest / sizeof digest[0];
  739.          dp < ep;
  740.          cp += 2)
  741.     (void) sprintf (cp, "%02x", *dp++ & 0xff);
  742.     *cp = NULL;
  743.  
  744.     if (strcmp (vec[2], buffer))
  745.     return respond (NOTOK, "authentication failure");
  746.  
  747.     return setup (pw, 0);
  748. }
  749. #endif
  750.  
  751. /*   */
  752.  
  753. static int setup (pw, guest)
  754. #ifndef    DPOP
  755. register struct passwd *pw;
  756. #else    /* DPOP */
  757. register struct bboard *pw;
  758. #endif    /* DPOP */
  759. int    guest;
  760. {
  761. #ifdef    BPOP
  762.     if (guest) {
  763.     (void) setgid (guest_gid);
  764. #ifndef    SYS5
  765.     (void) initgroups (popbbuser, guest_gid);
  766. #endif    /* SYS5 */
  767.     (void) setuid (guest_uid);
  768.     }
  769.     else {
  770. #endif    /* BPOP */
  771. #ifndef    DPOP
  772.     (void) setgid (pw -> pw_gid);
  773. #ifndef    SYS5
  774.     (void) initgroups (pw -> pw_name, pw -> pw_gid);
  775. #endif    /* SYS5 */
  776.     (void) setuid (pw -> pw_uid);
  777. #else    /* DPOP */
  778.     (void) setgid (pop_gid);
  779. #ifndef    SYS5
  780.     (void) initgroups (POPUID, pop_gid);
  781. #endif    /* SYS5 */
  782.     (void) setuid (pop_uid);
  783. #endif    /* DPOP */
  784. #ifdef    BPOP
  785.     }
  786. #endif    /* BPOP */
  787.  
  788. #ifndef    DPOP
  789.     (void) sprintf (maildrop, "%s/%s",
  790.         mmdfldir && *mmdfldir ? mmdfldir : pw -> pw_dir,
  791.         mmdflfil && *mmdflfil ? mmdflfil : pw -> pw_name);
  792. #else    /* DPOP */
  793.     (void) strcpy (maildrop, pw -> bb_file);
  794. #endif    /* DPOP */
  795.  
  796.     if (setupaux (guest) == NOTOK)
  797.     return NOTOK;
  798.  
  799. #ifdef    POP2
  800.     if (pop2 != NOTOK) {        /* in response to pop2 "helo" */
  801.     pop2 = nmsgs > 0 ? 1 : 0;
  802.     return respond ('#', "%d message%s (%d octets)",
  803.         nmsgs, nmsgs != 1 ? "s" : "", Msgs[0].m_size);
  804.     }
  805.     else
  806. #endif    /* POP2 */
  807.     return respond (OK,
  808.         nmsgs ? "maildrop has %d message%s (%d octets)" : "maildrop empty",
  809.         nmsgs, nmsgs != 1 ? "s" : "", Msgs[0].m_size);
  810. }
  811.  
  812. /*   */
  813.  
  814. static int  setupaux (readonly)
  815. int    readonly;
  816. {
  817.     register int    i,
  818.                     msgp;
  819.     struct stat st;
  820.  
  821. #ifdef    BPOP
  822.     xtnded = 0;
  823. #endif    /* BPOP */
  824.     if ((dp = readonly ? fopen (maildrop, "r") : lkfopen (maildrop, "r"))
  825.         == NULL)
  826.     switch (errno) {
  827.         case ENOENT: 
  828.         m_gMsgs (msgp = 0);
  829.         goto no_mail;
  830.  
  831.         default: 
  832.         nmsgs = dmsgs = 0;
  833.         return respond (NOTOK, "unable to %s maildrop: \"%s\"",
  834.             readonly ? "read" : "lock", maildrop);
  835.     }
  836.  
  837.     if (fstat (fileno (dp), &st) != NOTOK) {
  838.     mode = (int) (st.st_mode & 0777), mtime = st.st_mtime;
  839.     msgp = read_map (maildrop, (long) st.st_size);
  840.     }
  841.     else {
  842.     mode = 0600, mtime = 0;
  843.     msgp = 0;
  844.     }
  845.  
  846.     if ((msgp = read_file (msgp ? Msgs[msgp].m_stop : 0L, msgp + 1)) < 1)
  847.     m_gMsgs (0);
  848.  
  849. no_mail: ;
  850.     lastseen = Msgs[0].m_last;
  851. if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: lastseen=%d",lastseen);
  852.     dmsgs = rmsgs = 0;
  853.     nmsgs = msgp;
  854.  
  855.     Msgs[0].m_flags = readonly ? MREAD : MNULL;
  856.     Msgs[0].m_size = 0;
  857.     for (i = 1; i <= nmsgs; i++) {
  858.     if (Msgs[i].m_size == 0)
  859.         Msgs[i].m_size = pmbx_size (i);
  860.     Msgs[0].m_size += Msgs[i].m_size;
  861.     Msgs[i].m_flags = MNULL;
  862.     }
  863.  
  864.     return OK;
  865. }
  866.  
  867. /*   */
  868.  
  869. static int  read_map (file, pos)
  870. char   *file;
  871. long    pos;
  872. {
  873.     register int    i,
  874.                     msgp;
  875.     register struct drop   *pp,
  876.                            *mp;
  877.     struct drop *rp;
  878.  
  879.     if (debug)
  880.     padvise (NULLCP, LOG_DEBUG, "read_map (%s, %ld)", file, pos);
  881.  
  882.     if ((i = map_read (file, pos, &rp, debug)) == 0)
  883.     return 0;
  884.  
  885.     m_gMsgs (i);
  886.  
  887.     Msgs[0].m_last = rp -> d_start;
  888.  
  889.     msgp = 1;
  890.     for (pp = rp + 1; i-- > 0; msgp++, pp++) {
  891.     mp = &Msgs[msgp].m_drop;
  892.     mp -> d_id = pp -> d_id;
  893.     mp -> d_size = pp -> d_size;
  894.     mp -> d_start = pp -> d_start;
  895.     mp -> d_stop = pp -> d_stop;
  896.     }
  897.     free ((char *) rp);
  898.  
  899.     if (Msgs[0].m_last > msgp) {
  900.     if (debug)
  901.         padvise (NULLCP, LOG_DEBUG, "lastseen adjusted from %d to %d",
  902.         Msgs[0].m_last, msgp);
  903.     Msgs[0].m_last = msgp;
  904.     }
  905.  
  906.     return (msgp - 1);
  907. }
  908.  
  909. /*   */
  910.  
  911. static int  read_file (pos, msgp)
  912. register long    pos;
  913. register int    msgp;
  914. {
  915.     register int    i;
  916.     register struct drop   *pp,
  917.                            *mp;
  918.     struct drop *rp;
  919.  
  920.     if (debug)
  921.     padvise (NULLCP, LOG_DEBUG, "read_file (%ld, %d)",
  922.         pos, msgp);
  923.  
  924.     if ((i = MBX_READ (dp, pos, &rp, debug)) <= 0)
  925.     return (msgp - 1);
  926.  
  927.     m_gMsgs ((msgp - 1) + i);
  928.  
  929.     for (pp = rp; i-- > 0; msgp++, pp++) {
  930.     mp = &Msgs[msgp].m_drop;
  931.     mp -> d_id = 0;
  932.     mp -> d_size = pp -> d_size;
  933.     mp -> d_start = pp -> d_start;
  934.     mp -> d_stop = pp -> d_stop;
  935.     }
  936.     free ((char *) rp);
  937.  
  938.     return (msgp - 1);
  939. }
  940.  
  941. /*   */
  942.  
  943. static m_gMsgs (n)
  944. int    n;
  945. {
  946.     if (debug)
  947.     padvise (NULLCP, LOG_DEBUG, "m_gMsgs (%d) 0x%x %d",
  948.         n, Msgs, nMsgs);
  949.  
  950.     if (Msgs == NULL) {
  951.     nMsgs = n + MAXFOLDER / 2;
  952.     Msgs = (struct Msg *) calloc ((unsigned) (nMsgs + 2), sizeof *Msgs);
  953.     if (Msgs == NULL)
  954.         padios (NULLCP, "unable to allocate Msgs structure");
  955.     return;
  956.     }
  957.  
  958.     if (nMsgs >= n)
  959.     return;
  960.  
  961.     nMsgs = n + MAXFOLDER / 2;
  962.     Msgs = (struct Msg *) realloc ((char *) Msgs,
  963.                 (unsigned) (nMsgs + 2) * sizeof *Msgs);
  964.     if (Msgs == NULL)
  965.     padios (NULLCP, "unable to reallocate Msgs structure");
  966. }
  967.  
  968. /*   */
  969.  
  970. static int  pmbx_size (m)
  971. register int     m;
  972. {
  973.     register int    i;
  974.     register long   pos;
  975.  
  976.     (void) fseek (dp, Msgs[m].m_start, 0);
  977.     for (i = 0, pos = Msgs[m].m_stop - Msgs[m].m_start; pos > 0; i++, pos--)
  978.     if (fgetc (dp) == '\n')
  979.         i++;
  980.  
  981.     return i;
  982. }
  983.  
  984. /*   */
  985.  
  986. /* ARGSUSED */
  987.  
  988. static int  status (vec)
  989. char  **vec;
  990. {
  991.     return respond (OK, "%d %d", nmsgs - dmsgs, Msgs[0].m_size);
  992. }
  993.  
  994.  
  995. #ifdef    POP2
  996. static int  rdp2 (vec)        /* always returns OK */
  997. char  **vec;
  998. {
  999.     if (vec[1]) {
  1000.     if ((pop2 = atoi (vec[1])) <= 0)
  1001.         pop2 = 0;
  1002.     }
  1003.     else if (pop2 == 0)
  1004.     return NOTOK;        /* close 'em down */
  1005.  
  1006.     if (pop2 <= 0 || pop2 > nmsgs) {
  1007.     pop2 = 0;
  1008.     return respond ('=', "0 no message"); 
  1009.     }
  1010.     if (Msgs[pop2].m_flags & MDELE) {
  1011.     pop2 = 0;
  1012.     return respond ('=', "0 message %d is deleted", pop2);
  1013.     }
  1014.  
  1015.     return respond ('=', "%d (message %d)", Msgs[pop2].m_size, pop2);
  1016. }
  1017.  
  1018. static int  ack2 (vec)
  1019. char   **vec;
  1020. {
  1021.     if (strcmp (vec[0], "ackd") == 0) {
  1022.     Msgs[pop2].m_flags |= MDELE;    /* ignored later if MREAD */
  1023.     Msgs[0].m_size -= Msgs[pop2].m_size;
  1024.     dmsgs++;
  1025.     }
  1026.  
  1027.     if (pop2) {        /* a current msg */
  1028.     rmsgs++;            /* mark this one as read */
  1029.     if (++pop2 > nmsgs)
  1030.         pop2 = -1;            /* let rdp2 reset */
  1031.     else if (Msgs[pop2].m_flags & MDELE)
  1032.         pop2 = -1;            /* let rdp2 reset */
  1033.     if (pop2 > Msgs[0].m_last)
  1034.         Msgs[0].m_last = pop2;
  1035.     }
  1036.     return rdp2 (vec);        /* vec = { "acks", 0 } */
  1037. }
  1038.  
  1039. static int  fold (vec)
  1040. register char  **vec;
  1041. {
  1042.     pop2 = 0;
  1043.  
  1044. #ifdef    notdef        
  1045.  
  1046. /* This might work, or it might be a huge security hole.  For my purpose,
  1047.  * it doesn't need to work, so I'm not going to make sure it's OK.
  1048.  * 16Nov90/JLR
  1049.  */
  1050.    
  1051.     if (quitaux (NULLVP) == NOTOK)
  1052.     return respond ('#', "0 unable to close folder");
  1053.     
  1054.     (void) sprintf (maildrop, vec[1]);
  1055.     if (setupaux (access (maildrop, 2) ? 1 : 0) == NOTOK)
  1056.     return respond ('#', "0 unable to read %s", maildrop);
  1057.  
  1058.     pop2 = nmsgs > 0 ? 1 : 0;
  1059.     return respond ('#', "%d message%s in %s (%d octets)",
  1060.         nmsgs, nmsgs != 1 ? "s" : "", maildrop, Msgs[0].m_size);
  1061.     
  1062. #endif
  1063.  
  1064.     respond ('#', "0 unable to change folders");
  1065.     return NOTOK;
  1066. }
  1067. #endif    /* POP2 */
  1068.  
  1069. static int  list (vec)
  1070. register char  **vec;
  1071. {
  1072.     register int    i;
  1073.  
  1074.     if (vec[1]) {
  1075.     if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
  1076.         return respond (NOTOK, "no such message: \"%s\"", vec[1]);
  1077.     if (Msgs[i].m_flags & MDELE)
  1078.         return respond (NOTOK, "message %d is deleted", i);
  1079.  
  1080. #ifndef    BPOP
  1081.     return respond (OK, "%d %d", i, Msgs[i].m_size);
  1082. #else    /* BPOP */
  1083. #ifdef    MPOP
  1084.     if (nfs && !xtnded) {
  1085.         char   *cp;
  1086.  
  1087.         (void) fseek (dp, Msgs[i].m_start, 0);
  1088.  
  1089.         switch (scan (dp, i, 0, nfs, 0, 0, NULLCP,
  1090.               (long) Msgs[i].m_size, 0)) {
  1091.         case SCNMSG:
  1092.         case SCNENC:
  1093.         case SCNERR:
  1094.             if (cp = index (scanl, '\n'))
  1095.             *cp = NULL;
  1096.             return respond (OK, "%d %d #%s",
  1097.                     i, Msgs[i].m_size, scanl);
  1098.  
  1099.         case SCNEOF:
  1100.             return respond (OK, "%d %d #%*d  empty",
  1101.                     i, Msgs[i].m_size, DMAXFOLDER, i);
  1102.  
  1103.         default:
  1104.             break;
  1105.         }
  1106.     }
  1107. #endif /* MPOP */
  1108.     return respond (OK, xtnded ? "%d %d %d" : "%d %d",
  1109.             i, Msgs[i].m_size, Msgs[i].m_id);
  1110. #endif    /* BPOP */
  1111.     }
  1112.  
  1113.     (void) respond (OK, "%d message%s (%d octets)",
  1114.         nmsgs - dmsgs, nmsgs - dmsgs != 1 ? "s" : "",
  1115.         Msgs[0].m_size);
  1116.     for (i = 1; i <= nmsgs; i++)
  1117.     if (!(Msgs[i].m_flags & MDELE)) {
  1118. #ifndef BPOP
  1119.         multiline ("%d %d", i, Msgs[i].m_size);
  1120. #else    /* BPOP */
  1121. #ifdef    MPOP
  1122.         if (nfs && !xtnded) {
  1123.         char   *cp;
  1124.  
  1125.         (void) fseek (dp, Msgs[i].m_start, 0);
  1126.  
  1127.         switch (scan (dp, i, 0, nfs, 0, 0, NULLCP,
  1128.                   (long) Msgs[i].m_size, 0)) {
  1129.             case SCNMSG:
  1130.             case SCNENC:
  1131.             case SCNERR:
  1132.                 if (cp = index (scanl, '\n'))
  1133.                 *cp = NULL;
  1134.                 multiline ("%d %d #%s",
  1135.                    i, Msgs[i].m_size, scanl);
  1136.             continue;
  1137.  
  1138.             case SCNEOF:
  1139.             multiline ("%d %d #%*d  empty",
  1140.                    i, Msgs[i].m_size, DMAXFOLDER, i);
  1141.             continue;
  1142.  
  1143.             default:
  1144.             break;
  1145.         }
  1146.         }
  1147. #endif /* MPOP */
  1148.         multiline (xtnded ? "%d %d %d" : "%d %d",
  1149.                i, Msgs[i].m_size, Msgs[i].m_id);
  1150. #endif    /* BPOP */
  1151.     }
  1152.     multiend ();
  1153.  
  1154.     return OK;
  1155. }
  1156.  
  1157. /*   */
  1158.  
  1159. static int  retrieve (vec)
  1160. register char  **vec;
  1161. {
  1162.     register int    i;
  1163.     register long   pos;
  1164.     register char  *cp;
  1165.     char    buffer[BUFSIZ];
  1166.  
  1167. #ifdef    POP2
  1168.   if (pop2 == 0)
  1169.     return NOTOK;
  1170.   else if (pop2 == NOTOK) {
  1171. #endif
  1172.     if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
  1173.     return respond (NOTOK, "no such message: \"%s\"", vec[1]);
  1174.     if (Msgs[i].m_flags & MDELE)
  1175.     return respond (NOTOK, "message %d is deleted", i);
  1176.  
  1177.     (void) respond (OK, "%d octets", Msgs[i].m_size);
  1178. #ifdef    POP2
  1179.   }
  1180.   else        /* if called by pop2, vec = { "retr", 0 } */
  1181.     i = pop2;
  1182. #endif
  1183.  
  1184.     for ((void) fseek (dp, pos = Msgs[i].m_start, 0);
  1185.         fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop;
  1186.         pos += (long) (cp - buffer + 1)) {
  1187.     if (*(cp = buffer + strlen (buffer) - 1) == '\n')
  1188.         *cp = 0;
  1189.     multiline ("%s", buffer);
  1190.     }
  1191. #ifdef    POP2
  1192.   if (pop2 == NOTOK) {        /* then multiend */
  1193. #endif
  1194.     multiend ();
  1195.  
  1196.     if (i > Msgs[0].m_last) {
  1197.     Msgs[0].m_last = i; 
  1198.     rmsgs++;
  1199.     }
  1200. #ifdef    POP2
  1201.   }
  1202. #endif
  1203.  
  1204.     return OK;
  1205. }
  1206.  
  1207. /*   */
  1208.  
  1209. static int  delete (vec)
  1210. register char   **vec;
  1211. {
  1212.     register int    i;
  1213.  
  1214.     if (Msgs[0].m_flags & MREAD)
  1215.     return respond (NOTOK, "maildrop is read-only");
  1216.  
  1217.     if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
  1218.     return respond (NOTOK, "no such message: \"%s\"", vec[1]);
  1219.     if (Msgs[i].m_flags & MDELE)
  1220.     return respond (NOTOK, "message %d is deleted", i);
  1221.  
  1222.     Msgs[i].m_flags |= MDELE;
  1223.     Msgs[0].m_size -= Msgs[i].m_size;
  1224.     dmsgs++;
  1225.  
  1226.     if (i > Msgs[0].m_last)
  1227.     Msgs[0].m_last = i;
  1228.  
  1229.     return respond (OK, "message %d deleted (%d octets)", i, Msgs[i].m_size);
  1230. }
  1231.  
  1232.  
  1233. static int  reset (vec)
  1234. char   **vec;
  1235. {
  1236.     register int    i;
  1237.  
  1238.     for (i = 1; i <= nmsgs; i++)
  1239.     if (Msgs[i].m_flags & MDELE) {
  1240.         Msgs[i].m_flags &= ~MDELE;
  1241.         Msgs[0].m_size += Msgs[i].m_size;
  1242.         dmsgs--;
  1243.     }
  1244.  
  1245.     Msgs[0].m_last = lastseen;
  1246.  
  1247. #ifdef    MPOP
  1248. #ifdef    BPOP
  1249.     if (nfs) {
  1250.     if (scanl)
  1251.         free (scanl), scanl = NULL;
  1252.     free (nfs), nfs = NULL;
  1253.     }
  1254. #endif
  1255. #endif /* MPOP */
  1256.  
  1257.     return status (vec);
  1258. }
  1259.  
  1260. /*   */
  1261.  
  1262. static int  top (vec)
  1263. register char  **vec;
  1264. {
  1265.     register int    i,
  1266.                     j,
  1267.                     body,
  1268.                     lines;
  1269.     register long   pos;
  1270.     register char  *cp;
  1271.     char    buffer[BUFSIZ];
  1272.  
  1273.     if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
  1274.     return respond (NOTOK, "no such message: \"%s\"", vec[1]);
  1275.     if (Msgs[i].m_flags & MDELE)
  1276.     return respond (NOTOK, "message %d is deleted", i);
  1277.     if ((j = atoi (vec[2])) < 0)
  1278.     return respond (NOTOK, "bad number: \"%s\"", vec[2]);
  1279.  
  1280.     (void) respond (OK, vec[0]);
  1281.  
  1282.     body = lines = 0;
  1283.     for ((void) fseek (dp, pos = Msgs[i].m_start, 0);
  1284.         fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop;
  1285.         pos += (long) (cp - buffer + 1)) {
  1286.     if (*(cp = buffer + strlen (buffer) - 1) == '\n')
  1287.         *cp = 0;
  1288.     if (body) {
  1289.         if (lines++ >= j)
  1290.         break;
  1291.     }
  1292.     else
  1293.         if (*buffer == 0)
  1294.         body++;
  1295.     multiline ("%s", buffer);
  1296.     }
  1297.     multiend ();
  1298.  
  1299.     return OK;
  1300. }
  1301.  
  1302. /*   */
  1303.  
  1304. /* ARGSUSED */
  1305.  
  1306. static int  last (vec)  
  1307. char  **vec;
  1308. {
  1309.     return respond (OK, "%d is the last msg seen", Msgs[0].m_last);
  1310. }
  1311.  
  1312. /*   */
  1313.  
  1314. #ifdef    BPOP
  1315. static int  xtnd (vec)
  1316. register char    **vec;
  1317. {
  1318.     make_lower (vec[1], vec[1]);
  1319.  
  1320.     if (strcmp (vec[1], "bboards") == 0 || strcmp (vec[1], "archive") == 0)
  1321.     return xtnd1 (vec);
  1322.     if (strcmp (vec[1], "x-bboards") == 0)
  1323.     return xtnd2 (vec);
  1324. #ifdef    MPOP
  1325.     if (strcmp (vec[1], "scan") == 0)
  1326.     return xtnd3 (vec);
  1327. #endif /* MPOP */
  1328.  
  1329.     return respond (NOTOK, "unknown XTND command: \"%s\"", vec[1]);
  1330. }
  1331.  
  1332.  
  1333. static int  xtnd1 (vec)
  1334. register char    **vec;
  1335. {
  1336.     register struct bboard *bb;
  1337.  
  1338.     if (vec[2]) {
  1339.     make_lower (vec[2], vec[2]);
  1340.     if ((bb = getbbaux (vec[2])) == NULL)
  1341.         return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]);
  1342.  
  1343.     if (quitaux (NULLVP) == NOTOK)
  1344.         return NOTOK;
  1345.     (void) strcpy (maildrop,
  1346.         strcmp (vec[1], "bboards") ? bb -> bb_archive : bb -> bb_file);
  1347.     if (setupaux (TRUE) == NOTOK)
  1348.         return NOTOK;
  1349.     xtnded++;
  1350.     (void) respond (OK, "%s", vec[1]);
  1351.     multiline ("%s %d", bb -> bb_name, bb -> bb_maxima);
  1352.     }
  1353.     else {
  1354.     if (strcmp (vec[1], "bboards"))
  1355.         return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]);
  1356.  
  1357.     (void) respond (OK, "%s", vec[1]);
  1358.     for (bb = BBhead; bb; bb = bb -> bb_next) {
  1359.         getbbmax (bb);
  1360.         if (!(bb -> bb_flags & BB_INVIS))
  1361.         multiline ("%s %d", bb -> bb_name, bb -> bb_maxima);
  1362.     }
  1363.     while (bb = getbbaux (NULLCP))
  1364.         if (!(bb -> bb_flags & BB_INVIS))
  1365.         multiline ("%s %d", bb -> bb_name, bb -> bb_maxima);
  1366.     }
  1367.     multiend ();
  1368.  
  1369.     return OK;
  1370. }
  1371.  
  1372. /*   */
  1373.  
  1374. static int  xtnd2 (vec)
  1375. register char     **vec;
  1376. {
  1377.     register char  *cp,
  1378.                   **ap;
  1379.     char    buffer[BUFSIZ];
  1380.     register struct bboard *bb;
  1381.  
  1382.     if (vec[2] == NULL)
  1383.     return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]);
  1384.  
  1385.     make_lower (vec[2], vec[2]);
  1386.     if ((bb = getbbaux (vec[2])) == NULL)
  1387.     return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]);
  1388.  
  1389.     (void) respond (OK, "%s", vec[1]);
  1390.     multiline ("%s", bb -> bb_name);
  1391.  
  1392.     cp = buffer;
  1393.     for (ap = bb -> bb_aka; *ap; ap++) {
  1394.     (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap);
  1395.     cp += strlen (cp);
  1396.     }
  1397.     multiline ("%s", buffer);
  1398.  
  1399.     multiline ("%s", bb -> bb_file);
  1400.     multiline ("%s", bb -> bb_archive);
  1401.     multiline ("%s", bb -> bb_info);
  1402.     multiline ("%s", bb -> bb_map);
  1403.     multiline ("%s", bb -> bb_passwd);
  1404.  
  1405.     cp = buffer;
  1406.     for (ap = bb -> bb_leader; *ap; ap++) {
  1407.     (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap);
  1408.     cp += strlen (cp);
  1409.     }
  1410.     multiline ("%s", buffer);
  1411.  
  1412.     multiline ("%s", bb -> bb_addr);
  1413.     multiline ("%s", bb -> bb_request);
  1414.     multiline ("%s", bb -> bb_relay);
  1415.  
  1416.     cp = buffer;
  1417.     for (ap = bb -> bb_dist; *ap; ap++) {
  1418.     (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap);
  1419.     cp += strlen (cp);
  1420.     }
  1421.     multiline ("%s", buffer);
  1422.  
  1423.     getbbmax (bb);
  1424.     multiline ("0%o %d", bb -> bb_flags, bb -> bb_maxima);
  1425.     multiline ("%s", bb -> bb_date);
  1426.  
  1427.     multiend ();
  1428.  
  1429.     return OK;
  1430. }
  1431.  
  1432. /*   */
  1433.  
  1434. static struct bboard *getbbaux (s)
  1435. register char   *s;
  1436. {
  1437.     register struct bboard *bb;
  1438.     struct stat st;
  1439.  
  1440.     if (BBhead == NULL)
  1441.     if (setbbinfo (BBOARDS, BBDB, 1))
  1442.         BBtime = getbbtime ();
  1443.     else
  1444.         return NULL;
  1445.  
  1446.     if (s != NULLCP)
  1447.     for (bb = BBhead; bb; bb = bb -> bb_next)
  1448.         if (strcmp (bb -> bb_name, s) == 0) {
  1449.         if (debug)
  1450.             padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from cache",
  1451.                 bb -> bb_name);
  1452.         getbbmax (bb);
  1453.         return bb;
  1454.         }
  1455.  
  1456.     while (bb = getbbent ()) {
  1457.     if ((bb = getbbcpy (bb)) == NULL)
  1458.         return NULL;
  1459.  
  1460.     if (access (bb -> bb_file, 04) == NOTOK && errno == EACCES)
  1461.         bb -> bb_flags |= BB_INVIS;
  1462.     bb -> bb_mtime = stat (bb -> bb_info, &st) != NOTOK ? st.st_mtime : 0L;
  1463.  
  1464.     if (BBtail != NULL)
  1465.         BBtail -> bb_next = bb;
  1466.     if (BBhead == NULL)
  1467.         BBhead = bb;
  1468.     BBtail = bb;
  1469.  
  1470.     if (s == NULL || strcmp (bb -> bb_name, s) == 0) {
  1471.         if (s && debug)
  1472.         padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from scratch",
  1473.             bb -> bb_name);
  1474.         return bb;
  1475.     }
  1476.     }
  1477.  
  1478.     return NULL;
  1479. }
  1480.  
  1481. /*   */
  1482.  
  1483. static  getbbmax (bb)
  1484. register struct bboard *bb;
  1485. {
  1486.     int     i;
  1487.     register char  *cp;
  1488.     char    buffer[BUFSIZ];
  1489.     struct stat st;
  1490.     register    FILE * fp;
  1491.  
  1492.     if (debug)
  1493.     padvise (NULLCP, LOG_DEBUG, "getbbmax: \"%s\", 0%o, %d, %s",
  1494.         bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date);
  1495.  
  1496.     if (!(bb -> bb_flags & BB_INVIS)
  1497.         && access (bb -> bb_file, 04) == NOTOK && errno == EACCES)
  1498.     bb -> bb_flags |= BB_INVIS;
  1499.  
  1500.     if (stat (bb -> bb_info, &st) == NOTOK
  1501.         || bb -> bb_mtime == st.st_mtime
  1502.         || (fp = fopen (bb -> bb_info, "r")) == NULL)
  1503.     return;
  1504.     bb -> bb_mtime = st.st_mtime;
  1505.  
  1506.     if (fgets (buffer, sizeof buffer, fp) && (i = atoi (buffer)) > 0)
  1507.     bb -> bb_maxima = i;
  1508.     if (!feof (fp) && fgets (buffer, sizeof buffer, fp)) {
  1509.     if (bb -> bb_date)
  1510.         free (bb -> bb_date);
  1511.     if (cp = index (buffer, '\n'))
  1512.         *cp = NULL;
  1513.     bb -> bb_date = getcpy (buffer);
  1514.     }
  1515.  
  1516.     (void) fclose (fp);
  1517.  
  1518.     if (debug)
  1519.     padvise (NULLCP, LOG_DEBUG, "updated: \"%s\", 0%o, %d, %s",
  1520.         bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date);
  1521. }
  1522.  
  1523. /*   */
  1524.  
  1525. #ifdef    MPOP
  1526. static int xtnd3 (vec)
  1527. register char **vec;
  1528. {
  1529.     if (vec[2] == NULL)
  1530.     return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]);
  1531.     if ((_sc_width = atoi (vec[2])) < WIDTH / 2)
  1532.     _sc_width = WIDTH / 2;
  1533.     nfs = new_fs (NULLCP, vec[3], FORMAT);
  1534.     if (scanl)
  1535.     (void) free (scanl), scanl = NULL;
  1536.  
  1537.     return respond (OK, vec[1]);
  1538. }
  1539.  
  1540. int    sc_width () { return _sc_width; }
  1541. #endif /* MPOP */
  1542. #endif    /* BPOP */
  1543.  
  1544. /*   */
  1545.  
  1546. static int  quit (vec)
  1547. char   **vec;
  1548. {
  1549.     int     d,
  1550.             n;
  1551.  
  1552.     d = dmsgs, n = nmsgs;
  1553.  
  1554.     if (quitaux (vec) == NOTOK)
  1555.     return NOTOK;
  1556.  
  1557. #ifdef    BPOP
  1558.     if (xtnded)
  1559.     return respond (OK, "%s signing off", server);
  1560. #endif    /* BPOP */
  1561.  
  1562.     if (n == d)
  1563.     return respond (OK, "%s signing off (maildrop empty)", server);
  1564.  
  1565.     return respond (OK,
  1566.         n ? "%s signing off (%d message%s, %d octets left)"
  1567.         : "%s signing off (maildrop empty)",
  1568.         server, n - d, n - d != 1 ? "s" : "", Msgs[0].m_size);
  1569. }
  1570.  
  1571.  
  1572. static int  quitaux (vec)
  1573. char   **vec;
  1574. {
  1575.     int     i;
  1576.  
  1577.     if (dp == NULL)
  1578.     return OK;
  1579.  
  1580.     i = quitfile (vec);
  1581.  
  1582.     nmsgs = dmsgs = rmsgs = 0;
  1583.     (void) lkfclose (dp, maildrop);
  1584.     dp = NULL;
  1585.  
  1586.     return i;
  1587. }
  1588.  
  1589. /*   */
  1590.  
  1591. /* ARGSUSED */
  1592.  
  1593. static int  quitfile (vec)
  1594. char   **vec;
  1595. {
  1596.     register int    i,
  1597.             j,
  1598.             tmpDR,
  1599.                     md;
  1600.     char    tmpfil[BUFSIZ],
  1601.             map1[BUFSIZ],
  1602.             map2[BUFSIZ];
  1603.     struct stat st;
  1604.  
  1605. if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: dmsgs=%d rmsgs=%d readonly=%d",
  1606.          dmsgs, rmsgs, Msgs[0].m_flags & MREAD);
  1607.  
  1608.     if (dmsgs == 0 || (Msgs[0].m_flags & MREAD))
  1609.     return OK;
  1610.  
  1611.     if (fstat (fileno (dp), &st) == NOTOK)
  1612.     return respond (NOTOK, "unable to stat file");
  1613.     if (mtime != st.st_mtime)
  1614.     return respond (NOTOK, "new messages have arrived, no update");
  1615.     mode = (int) (st.st_mode & 0777);
  1616.  
  1617.     if (nmsgs == dmsgs) {
  1618. #ifndef    SYS5
  1619.     i = truncate (maildrop, 0);
  1620. #else    /* SYS5 */
  1621.     i = open (maildrop, O_WRONLY | O_TRUNC);
  1622.     if (i != NOTOK) (void) close (i);
  1623. #endif    /* SYS5 */
  1624.     (void) unlink (map_name (maildrop));/* XXX */
  1625.     if (i == NOTOK)
  1626.         return respond (NOTOK, "unable to zero %s", maildrop);
  1627.     return OK;
  1628.     }
  1629.  
  1630.     (void) strcpy (tmpfil, m_backup (maildrop));
  1631.     if ((md = mbx_open (tmpfil, st.st_uid, st.st_gid, mode)) == NOTOK)
  1632.       { char msgbuf0[256];
  1633.         sprintf(msgbuf0,"unable to create temporary file (%s)",tmpfil);
  1634.         return respond (NOTOK, msgbuf0);
  1635.           }
  1636.  
  1637.     j = 0, tmpDR = Msgs[0].m_last;
  1638. if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: last=%d",Msgs[0].m_last);
  1639.     for (i = 1; i <= nmsgs; i++) {
  1640.     if (!(Msgs[i].m_flags & MDELE))
  1641.         j++;
  1642.     if (i == tmpDR)
  1643.         Msgs[0].m_last = j;
  1644.     }
  1645. if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: last=%d",Msgs[0].m_last);
  1646.  
  1647.     for (i = 1; i <= nmsgs; i++)
  1648.     if (!(Msgs[i].m_flags & MDELE)
  1649.         &&  mbx_write (tmpfil, md, dp, Msgs[i].m_id, Msgs[0].m_last,
  1650.             Msgs[i].m_start, Msgs[i].m_stop, TRUE, debug)
  1651.                 == NOTOK) {
  1652.         (void) mbx_close (tmpfil, md);
  1653.         (void) unlink (tmpfil);
  1654.         return respond (NOTOK, "error writing temporary file");
  1655.     }
  1656.     (void) mbx_close (tmpfil, md);
  1657.  
  1658.     if ((i = rename (tmpfil, maildrop)) == OK) {
  1659.     (void) strcpy (map1, map_name (tmpfil));
  1660.     (void) strcpy (map2, map_name (maildrop));
  1661.     if (rename (map1, map2) == NOTOK) {
  1662.         (void) unlink (map1);
  1663.         (void) unlink (map2);
  1664.     }
  1665.     }
  1666.  
  1667.     if (i == NOTOK)
  1668.     return respond (NOTOK, "unable to rename maildrop");
  1669.  
  1670.     return OK;
  1671. }
  1672.  
  1673. /*   */
  1674.  
  1675. static struct vector   *getvector (bp, vec)
  1676. register char   *bp,
  1677.           **vec;
  1678. {
  1679.     register int    i;
  1680.     register struct vector *v;
  1681.  
  1682.     for (i = 0; i < NVEC; i++) {
  1683.     while (isspace (*bp))
  1684.         *bp++ = 0;
  1685.     if (*bp == 0) {
  1686.         vec[i] = NULL;
  1687.         break;
  1688.     }
  1689.  
  1690.     if (*bp == '"') {
  1691.         for (vec[i] = ++bp; *bp != '\0' && *bp != '"'; bp++)
  1692.         if (*bp == '\\') {
  1693.             switch (*++bp) {
  1694.             case 'n':
  1695.                 (void) strcpy (bp, bp + 1);
  1696.                 *--bp = '\n';
  1697.                 break;
  1698.  
  1699.             case '\\':
  1700.             case '"':
  1701.                 (void) strcpy (bp - 1, bp);
  1702.                 /* and fall... */
  1703.             default:
  1704.                 bp--;
  1705.                 break;
  1706.             }
  1707.         }
  1708.         if (*bp == '"')
  1709.         *bp++ = '\0';
  1710.         continue;
  1711.     }
  1712.     
  1713.     vec[i] = bp;
  1714.     while (!isspace (*bp))
  1715.         bp++;
  1716.     }
  1717.     i--;
  1718.     vec[NVEC] = NULL;
  1719.  
  1720.     if (*bp != 0) {
  1721.     (void) respond (NOTOK, "too many arguments");
  1722.     return NULL;
  1723.     }
  1724.     if (*vec[0] == 0) {
  1725.     (void) respond (NOTOK, "null command");
  1726.     return NULL;
  1727.     }
  1728.     make_lower (vec[0], vec[0]);
  1729.  
  1730.     for (v = vectors; v -> v_cmd; v++)
  1731.     if (strcmp (v -> v_cmd, vec[0]) == 0 && v -> v_valid == mystate) {
  1732.         if (i < v -> v_min || v -> v_max < i) {
  1733.         (void) respond (NOTOK, "too %s arguments to \"%s\"",
  1734.             i < v -> v_min ? "few" : "many", vec[0]);
  1735.         return NULL;
  1736.         }
  1737.         else
  1738.         return v;
  1739.     }
  1740.  
  1741.     (void) respond (NOTOK, "unknown command: \"%s\"", vec[0]);
  1742.     return NULL;
  1743. }
  1744.  
  1745. /*   */
  1746.  
  1747. /* VARARGS2 */
  1748.  
  1749. static int  respond (code, fmt, a, b, c, d)
  1750. char   *fmt,
  1751.        *a,
  1752.        *b,
  1753.        *c,
  1754.        *d;
  1755. int     code;
  1756. {
  1757.     register char  *bp;
  1758.     char    buffer[BUFSIZ];
  1759.  
  1760.     bp = buffer;
  1761. #ifndef    POP2
  1762.     (void) sprintf (bp, "%s%s", code == OK ? "+OK" : "-ERR", fmt ? " " : "");
  1763.     bp += strlen (bp);
  1764. #else
  1765.     switch (code) {
  1766.     case OK:
  1767.     case NOTOK:
  1768.         (void) sprintf (bp, "%s%s", code == OK ? "+OK" : "-ERR",
  1769.             fmt ? " " : "");
  1770.         bp += strlen (bp);
  1771.         break;
  1772.  
  1773.     default:        /* only happens in pop2 */
  1774.         *bp++ = code;
  1775.         code = OK;
  1776.     }
  1777. #endif
  1778.     if (fmt) {
  1779.     (void) sprintf (bp, fmt, a, b, c, d);
  1780.     bp += strlen (bp);
  1781.     }
  1782.     putline (buffer, output);
  1783.  
  1784.     return code;
  1785. }
  1786.  
  1787.  
  1788. /* VARARGS1 */
  1789.  
  1790. static  multiline (fmt, a, b, c, d)
  1791. char   *fmt,
  1792.        *a,
  1793.        *b,
  1794.        *c,
  1795.        *d;
  1796. {
  1797.     register char  *cp;
  1798.     char    buffer[BUFSIZ + TRMLEN];
  1799.  
  1800.     (void) strcpy (buffer, TRM);
  1801.     (void) sprintf (cp = (buffer + TRMLEN), fmt, a, b, c, d);
  1802.     if (strncmp (cp, TRM, TRMLEN) == 0)
  1803.     cp = buffer;
  1804.  
  1805.     putline (cp, output);
  1806. }
  1807.  
  1808.  
  1809. static  multiend () {
  1810.     putline (TRM, output);
  1811. }
  1812.  
  1813. /*   */
  1814.  
  1815. static int  getline (s, n, iop)
  1816. register char  *s;
  1817. register int    n;
  1818. register FILE  *iop;
  1819. {
  1820.     register int    c;
  1821.     register char  *p;
  1822.  
  1823.     p = s;
  1824.     while (--n > 0 && (c = fgetc (iop)) != EOF) {
  1825.     while (c == IAC) {
  1826.         (void) fgetc (iop);
  1827.         c = fgetc (iop);
  1828.     }
  1829.     if ((*p++ = c) == '\n')
  1830.         break;
  1831.     }
  1832.     if (ferror (iop))
  1833.     return NOTOK;
  1834.     if (c == EOF && p == s)
  1835.     return DONE;
  1836.     if (debug) {
  1837.     if (*--p == '\n')
  1838.         *p = 0;
  1839.     padvise (NULLCP, LOG_DEBUG, "<--- %s", s);
  1840.     if (*p == 0)
  1841.         *p = '\n';
  1842.     p++;
  1843.     }
  1844.     *p++ = 0;
  1845.  
  1846.     return OK;
  1847. }
  1848.  
  1849.  
  1850. static  putline (s, iop)
  1851. register char   *s;
  1852. register FILE   *iop;
  1853. {
  1854.     (void) fprintf (iop, "%s\r\n", s);
  1855.     if (debug)
  1856.     padvise (NULLCP, LOG_DEBUG, "---> %s", s);
  1857.  
  1858.     (void) fflush (iop);
  1859. }
  1860.  
  1861.  
  1862. /* ARGSUSED */
  1863.  
  1864. static int pipeser (sig, code, sc)
  1865. int    sig;
  1866. long    code;
  1867. struct sigcontext *sc;
  1868. {
  1869.     padvise (NULLCP, LOG_WARNING, "lost connection");
  1870.  
  1871.     _exit (NOTOK);
  1872. }
  1873.  
  1874. /*   */
  1875.  
  1876. /* Some people don't want to use the POP delivery agent with Sendmail
  1877.  * if they're going to run POP.  Sendmail writes maildrops in the old
  1878.  * UUCP format, and popd doesn't know how to read them.  These people
  1879.  * really should do what the MH manual says -- run the pop delivery
  1880.  * agent and be done with it.  Some things never die.
  1881.  *
  1882.  * A real fix would be to make uip/dropsbr.c should use the same methods
  1883.  * as sbr/m_getfld.c to determine the format of maildrops and read &
  1884.  * write them.  Unfortunately, it'll take a lot of work to bring it into
  1885.  * the fold.  20Mar90/JLR
  1886.  * 
  1887.  * I really really hate to add this, but this lets stuff popd read
  1888.  * UUCP style maildrops as well as MMDF (ctrl/A) style maildrops.  It was
  1889.  * contributed by Steve Dempsey <steved@longs.LANCE.ColoState.Edu>.
  1890.  *
  1891.  * Here's what he says:
  1892.  * 
  1893.  * Ideally, one should be able to do it with the mmdelim strings, but
  1894.  * the MH parser is not intelligent enough to do this.  You have at
  1895.  * least a couple of choices:
  1896.  * 
  1897.  *   - use aliases to deliver mail to POP users (user: user@pop) and
  1898.  *     install the POP delivery agent - should work well with sendmail.
  1899.  *   - fix the POP server!
  1900.  * 
  1901.  * We have all mail sent to one machine and users are given two options:
  1902.  * 
  1903.  *   - MH on any machine.
  1904.  *   - any user agent on the postoffice machine.
  1905.  * 
  1906.  * Most of our workstations run xmh and users find that to be sufficient.
  1907.  * New users are only taught to use MH, and a very few old timers stay
  1908.  * with BSD mail.  In any case, several agents are available at the cost
  1909.  * of a telnet/rlogin if a user does not like MH.
  1910.  * 
  1911.  * I have made the changes to the POP server (MH-6.6/support/pop/popser.c)
  1912.  * to look for the `\n\nFrom ' delimiter instead of the ^A's, using some
  1913.  * code from the BSD agent.  Context diff is included below.  When this
  1914.  * is installed, you just go back to the normal localmail and get rid of
  1915.  * slocal completely.
  1916.  * 
  1917.  * I have not tried this modification with anything but the MH client,
  1918.  * but it should work.  Nothing in the POP protocol changes; the server
  1919.  * just has different criteria for delimiting messages in the mailbox.
  1920.  * If you decide to use this, I'd like to know what happens.
  1921.  * 
  1922.  *         Steve Dempsey,  Center for Computer Assisted Engineering
  1923.  *   Colorado State University, Fort Collins, CO  80523    +1 303 491 0630
  1924.  * INET: steved@longs.LANCE.ColoState.Edu, dempsey@handel.CS.ColoState.Edu
  1925.  * boulder!ccncsu!longs.LANCE.ColoState.Edu!steved, ...!ncar!handel!dempsey
  1926.  */
  1927. /* From:    Jim Reid <jim@computer-science.strathclyde.ac.UK>
  1928.  * 
  1929.  * MH-6.7 does not support MMDF-style mailboxes with POP as claimed. It
  1930.  * appears that when code was added to popser.c to support UNIX-style
  1931.  * mailboxes, the old behaviour was lost. i.e. The new popd worked with
  1932.  * UNIX-style mailboxes, but not MMDF ones. Users would get "format error"
  1933.  * error messages if they tried to inc a remote MMDF-style mailbox because
  1934.  * the pop daemon didn't want to know or like the MMDF message delimiters.
  1935.  */
  1936.  
  1937. /* So... Now there's an incredible hack in mhconfig.c to define POPUUMBOX
  1938.  * in support/pop/Makefile if we're using Sendmail.  This causes this
  1939.  * UUCP-mbox reading code to be used here.  Ugh.  05Nov90/JLR
  1940.  */
  1941.  
  1942. /*   */
  1943. #ifdef    POPUUMBOX
  1944. /* from dropsbr.c - read from a mailbox - pop server version */
  1945.  
  1946. /* ALMOST IDENTICAL to mbx_read */
  1947.  
  1948. static    int    pmbx_read (fp, pos, drops, noisy)
  1949. register FILE  *fp;
  1950. register long    pos;
  1951. struct drop **drops;
  1952. int    noisy;
  1953. {
  1954.     register int    len,
  1955.                     size;
  1956.     register char  *bp;
  1957.     char    buffer[BUFSIZ];
  1958.     register struct drop   *cp,
  1959.                            *dp,
  1960.                            *ep,
  1961.                            *pp;
  1962.  
  1963. /* MTR: tsk, tsk, tsk... */
  1964.     (void) fseek (fp, pos, 0);
  1965.     if (fgets (buffer, sizeof buffer, fp)
  1966.         && strcmp (buffer, mmdlm1) == 0)
  1967.     return mbx_read (fp, pos, drops, noisy);
  1968.  
  1969.     /* get drop storage */
  1970.     pp = (struct drop  *) calloc ((unsigned) (len = MAXFOLDER), sizeof *dp);
  1971.  
  1972.     if (debug)
  1973.     padvise (NULLCP, LOG_DEBUG, "pmbx_read (%d, %ld, %d, %d)",
  1974.         fp, pos,drops,noisy);
  1975.  
  1976.     if (pp == NULL) {
  1977.     if (noisy)
  1978.         admonish (NULLCP, "unable to allocate drop storage");
  1979.     return NOTOK;
  1980.     }
  1981.  
  1982.     /* rewind drop file */
  1983.     (void) fseek (fp, pos, 0);
  1984.  
  1985.     if (debug)
  1986.     padvise (NULLCP, LOG_DEBUG, "rewind maildrop");
  1987.  
  1988.     /* read a buffer */
  1989.     for (ep = (dp = pp) + len - 1; fgets (buffer, sizeof buffer, fp);) {
  1990.     size = 0;
  1991.  
  1992.     /* if beginning of msg then mark it */
  1993.  
  1994.     if (p_ishead(buffer)) /*(strcmp (buffer, mmdlm1) == 0)*/ {
  1995.         /* (don't) inc pos to msg start, mark it */
  1996.         /*pos += ld1;*/
  1997.         dp -> d_start = pos;
  1998.         pos += strlen(buffer);  /* inc pos after marking head */
  1999.     }
  2000.     else {
  2001.         /* didn't find it; mark it anyway */
  2002.         dp -> d_start = pos, pos += (long) strlen (buffer);
  2003.  
  2004.         /* count newlines and inc size if any found */
  2005.         for (bp = buffer; *bp; bp++, size++)
  2006.         if (*bp == '\n')
  2007.             size++;
  2008.     }
  2009.  
  2010.     /* read more lines... */
  2011.     while (fgets (buffer, sizeof buffer, fp) != NULL)
  2012.  
  2013.         /* found end? */
  2014.         if (p_ishead(buffer)) /*(strcmp (buffer, mmdlm2) == 0)*/ {
  2015.  
  2016.         /* out of loop */
  2017.             (void) fseek (fp, pos, 0);
  2018.         break;
  2019.  
  2020.             }
  2021.         else {
  2022.         /* add buffer size to pos */
  2023.         pos += (long) strlen (buffer);
  2024.  
  2025.         /* count newlines.... */
  2026.         for (bp = buffer; *bp; bp++, size++)
  2027.             if (*bp == '\n')
  2028.             size++;
  2029.         }
  2030.  
  2031.     if (dp -> d_start != pos) {
  2032.         /* do this if pos was actually incremented; got some text */
  2033.         dp -> d_id = 0;
  2034.         dp -> d_size = size;  /* save the stuff we got */
  2035.         dp -> d_stop = pos;
  2036.         dp++;
  2037.     }
  2038.  
  2039.     /* (don't) advance pos */
  2040.     /* pos += ld2; */
  2041.  
  2042.     /* need more storage.... */
  2043.     if (dp >= ep) {
  2044.         register int    curlen = dp - pp;
  2045.  
  2046.         cp = (struct drop  *) realloc ((char *) pp,
  2047.                             (unsigned) (len += MAXFOLDER) * sizeof *pp);
  2048.         if (cp == NULL) {
  2049.         if (noisy)
  2050.             admonish (NULLCP, "unable to allocate drop storage");
  2051.         free ((char *) pp);
  2052.         return 0;
  2053.         }
  2054.         dp = cp + curlen, ep = (pp = cp) + len - 1;
  2055.     }
  2056.     }
  2057.  
  2058.     /* return unused stuff */
  2059.     if (dp == pp)
  2060.     free ((char *) pp);
  2061.     else
  2062.     *drops = pp;
  2063.     return (dp - pp);
  2064. }
  2065.  
  2066. /*
  2067.  * The remainder of this file adapted from:
  2068.  *
  2069.  *    head.c    5.2 (Berkeley) 6/21/85
  2070.  */
  2071.  
  2072. struct p_hdline {
  2073.     char    *l_from;    /* The name of the sender */
  2074.     char    *l_tty;        /* His tty string (if any) */
  2075.     char    *l_date;    /* The entire date string */
  2076. };
  2077.  
  2078. /*
  2079.  *
  2080.  * See if position in a file is a mail header.
  2081.  * Return true if yes.  Note the extreme pains to
  2082.  * accomodate all funny formats.
  2083.  */
  2084.  
  2085. #define    NOSTR        ((char *) 0)    /* Null string pointer */
  2086. static    char *p_copyin();
  2087. static    char *p_copy();
  2088.  
  2089.  
  2090. static    p_ishead(buffer)
  2091. char buffer[];
  2092. {
  2093. register char *cp;
  2094. struct p_hdline hl;
  2095. char linebuf[BUFSIZ];
  2096. char parbuf[BUFSIZ];
  2097.  
  2098.     strcpy(linebuf,buffer);
  2099.     cp = linebuf;
  2100.  
  2101.     if (linebuf[0]=='F')
  2102.           padvise (NULLCP, LOG_DEBUG, "ishead: '%s'",linebuf);
  2103.  
  2104.     if (strncmp("From ", cp, 5) != 0)
  2105.         return(0);
  2106.  
  2107.     padvise (NULLCP, LOG_DEBUG, "Fromline...");
  2108.  
  2109.     /* get full header */
  2110.     p_parse(cp, &hl, parbuf);
  2111.  
  2112.     if (hl.l_from == NOSTR || hl.l_date ==  NOSTR) {
  2113.           padvise (NULLCP, LOG_DEBUG, "Fromline...NODATE");
  2114.         return(0);
  2115.         }
  2116.  
  2117.     if (!p_isdate(hl.l_date)) {
  2118.           padvise (NULLCP, LOG_DEBUG, "Fromline...BADDATE %s",
  2119.             hl.l_date);
  2120.         return(0);
  2121.         }
  2122.  
  2123.     /* I guess we got it! */
  2124.     padvise (NULLCP, LOG_DEBUG, "got a head.. ");
  2125.  
  2126.     return(1);
  2127. }
  2128.  
  2129. /*
  2130.  * Split a headline into its useful components.
  2131.  * Copy the line into dynamic string space, then set
  2132.  * pointers into the copied line in the passed headline
  2133.  * structure.  Actually, it scans.
  2134.  */
  2135.  
  2136. static    p_parse(line, hl, pbuf)
  2137.     char line[], pbuf[];
  2138.     struct p_hdline *hl;
  2139. {
  2140.     register char *cp, *dp;
  2141.     char *sp;
  2142.     char word[BUFSIZ];
  2143.     char * p_nextword();
  2144.  
  2145.     hl->l_from = NOSTR;
  2146.     hl->l_tty = NOSTR;
  2147.     hl->l_date = NOSTR;
  2148.     cp = line;
  2149.     sp = pbuf;
  2150.  
  2151.     /*
  2152.      * Skip the first "word" of the line, which should be "From"
  2153.      * anyway.
  2154.      */
  2155.     cp = p_nextword(cp, word);
  2156.     dp = p_nextword(cp, word);
  2157.     if (!(strcmp(word, "")==0))
  2158.         hl->l_from = p_copyin(word, &sp);
  2159.  
  2160.     /* UNLIKELY */
  2161.     if (strncmp(dp, "tty", 3) == 0) {
  2162.         cp = p_nextword(dp, word);
  2163.         hl->l_tty = p_copyin(word, &sp);
  2164.         if (cp != NOSTR)
  2165.             hl->l_date = p_copyin(cp, &sp);
  2166.     }
  2167.  
  2168.     /* USUAL */
  2169.     else
  2170.         if (dp != NOSTR)
  2171.             hl->l_date = p_copyin(dp, &sp);
  2172. }
  2173.  
  2174. /*
  2175.  * Copy the string on the left into the string on the right
  2176.  * and bump the right (reference) string pointer by the length.
  2177.  * Thus, dynamically allocate space in the right string, copying
  2178.  * the left string into it.
  2179.  */
  2180.  
  2181. static    char *
  2182. p_copyin(src, space)
  2183.     char src[];
  2184.     char **space;
  2185. {
  2186.     register char *cp, *top;
  2187.     register int s;
  2188.  
  2189.     s = strlen(src);
  2190.     cp = *space;
  2191.     top = cp;
  2192.     strcpy(cp, src);
  2193.     cp += s + 1;
  2194.     *space = cp;
  2195.     return(top);
  2196. }
  2197.  
  2198. /*
  2199.  * Collect a liberal (space, tab delimited) word into the word buffer
  2200.  * passed.  Also, return a pointer to the next word following that,
  2201.  * or (empty) if none follow.
  2202.  */
  2203.  
  2204. static    char *
  2205. p_nextword(wp, wbuf)
  2206.     char wp[], wbuf[];
  2207. {
  2208.     register char *cp, *cp2;
  2209.  
  2210.     if ((cp = wp) == NOSTR) {
  2211.         p_copy("", wbuf);
  2212.         return(NOSTR);
  2213.     }
  2214.     cp2 = wbuf;
  2215.     while (!any(*cp, " \t") && *cp != '\0')
  2216.         if (*cp == '"') {
  2217.              *cp2++ = *cp++;
  2218.              while (*cp != '\0' && *cp != '"')
  2219.                  *cp2++ = *cp++;
  2220.              if (*cp == '"')
  2221.                  *cp2++ = *cp++;
  2222.          } else
  2223.              *cp2++ = *cp++;
  2224.     *cp2 = '\0';
  2225.     while (any(*cp, " \t"))
  2226.         cp++;
  2227.     if (*cp == '\0')
  2228.         return(NOSTR);
  2229.     return(cp);
  2230. }
  2231.  
  2232. /*
  2233.  * Copy str1 to str2, return pointer to null in str2.
  2234.  */
  2235.  
  2236. static    char *
  2237. p_copy(str1, str2)
  2238.     char *str1, *str2;
  2239. {
  2240.     register char *s1, *s2;
  2241.  
  2242.     s1 = str1;
  2243.     s2 = str2;
  2244.     while (*s1)
  2245.         *s2++ = *s1++;
  2246.     *s2 = 0;
  2247.     return(s2);
  2248. }
  2249.  
  2250. #define    L    1        /* A lower case char */
  2251. #define    S    2        /* A space */
  2252. #define    D    3        /* A digit */
  2253. #define    O    4        /* An optional digit or space */
  2254. #define    C    5        /* A colon */
  2255. #define    N    6        /* A new line */
  2256. #define U    7        /* An upper case char */
  2257.  
  2258. static    char p_ctypes[] = 
  2259.     {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0};
  2260. /*       T h u   S e p   2 9   1 5 : 2 0 : 1 9   1 9 8 8 */
  2261.  
  2262. static    char p_tmztyp[] = 
  2263.     {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0};
  2264. /*       T h u   S e p   2 9   1 5 : 2 0 : 1 9   M S T   1 9 8 8 */
  2265.  
  2266. static    p_isdate(date)
  2267.     char date[];
  2268. {
  2269.     register char *cp;
  2270.  
  2271.     cp = date;
  2272.     if (p_cmatch(cp, p_ctypes))
  2273.         return(1);
  2274.  
  2275.     return(p_cmatch(cp, p_tmztyp));
  2276. }
  2277.  
  2278. /*
  2279.  * Match the given string against the given template.
  2280.  * Return 1 if they match, 0 if they don't
  2281.  */
  2282.  
  2283. static    p_cmatch(str, temp)
  2284.     char str[], temp[];
  2285. {
  2286.     register char *cp, *tp;
  2287.     register int c;
  2288.  
  2289.     cp = str;
  2290.     tp = temp;
  2291.     while (*cp != '\0' && *tp != 0) {
  2292.         c = *cp++;
  2293.         switch (*tp++) {
  2294.         case L:
  2295.             if (c < 'a' || c > 'z')
  2296.                 return(0);
  2297.             break;
  2298.  
  2299.         case U:
  2300.             if (c < 'A' || c > 'Z')
  2301.                 return(0);
  2302.             break;
  2303.  
  2304.         case S:
  2305.             if (c != ' ')
  2306.                 return(0);
  2307.             break;
  2308.  
  2309.         case D:
  2310.             if (!isdigit(c))
  2311.                 return(0);
  2312.             break;
  2313.  
  2314.         case O:
  2315.             if (c != ' ' && !isdigit(c))
  2316.                 return(0);
  2317.             break;
  2318.  
  2319.         case C:
  2320.             if (c != ':')
  2321.                 return(0);
  2322.             break;
  2323.  
  2324.         case N:
  2325.             if (c != '\n')
  2326.                 return(0);
  2327.             break;
  2328.         }
  2329.     }
  2330.     if ((*cp != '\0' && *cp != '\n') || *tp != 0)
  2331.         return(0);
  2332.     return(1);
  2333. }
  2334.  
  2335. static    any(ch, str)
  2336.     char *str;
  2337. {
  2338.     register char *f;
  2339.     register c;
  2340.  
  2341.     f = str;
  2342.     c = ch;
  2343.     while (*f)
  2344.         if (c == *f++)
  2345.             return(1);
  2346.     return(0);
  2347. }
  2348. #endif
  2349.